package com.quectel.sys.module.sys.service.impl;


import cn.hutool.core.collection.CollectionUtil;
import com.quectel.constant.global.SystemConstants;
import com.quectel.sys.constants.RedisCacheConstants;
import com.quectel.sys.module.sys.dao.SysCodeDao;
import com.quectel.sys.module.sys.dto.SysCodeDto;
import com.quectel.sys.module.sys.entity.SysCodeEntity;
import com.quectel.sys.module.sys.service.SysCodeService;
import com.quectel.util.common.CopyUtils;
import com.quectel.util.kit.CacheKit;
import com.quectel.util.kit.Snowflake;
import com.quectel.util.mybatis.MyBatisPlusUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author rananxin
 * @date 2019-08-12 14:51:26
 */
@DubboService
public class SysCodeServiceImpl implements SysCodeService {

    private static final Logger LOGGER = LoggerFactory.getLogger(SysCodeServiceImpl.class);

    @Autowired
    private SysCodeDao sysCodeDao;

    public static void sortChildren(List<SysCodeDto> childrenList) {
        if (childrenList != null && childrenList.size() > 0) {
            childrenList.sort(new Comparator<SysCodeDto>() {
                @Override
                public int compare(SysCodeDto o1, SysCodeDto o2) {
                    if (o1.getSort() != null && o2.getSort() != null) {
                        return o1.getSort() - o2.getSort();
                    }
                    return 0;
                }
            });
            for (SysCodeDto sysCodeDto : childrenList) {
                if (sysCodeDto.getChildren() != null) {
                    sortChildren(sysCodeDto.getChildren());
                }
            }
        }
    }

    @Override
    public List<SysCodeDto> queryListByMark(String mark) {


        return CacheKit.cacheToRedis(
                () -> {
                    List<SysCodeEntity> codeEntityList = sysCodeDao.recursion(mark)
                            .stream()
                            .filter(v -> Objects.equals(v.getStatus(), SystemConstants.YES))
                            .collect(Collectors.toList());

                    List<SysCodeDto> list = CopyUtils.copyList(codeEntityList, SysCodeDto.class);

                    List<SysCodeDto> rootList = list.stream()
                            .filter(v -> Objects.equals(v.getStatus(), SystemConstants.YES))
                            .filter(v -> Objects.equals(v.getMark(), mark))
                            .collect(Collectors.toList());
                    List<SysCodeDto> resultList = treeBuilder(list, CollectionUtil.isNotEmpty(rootList) ? rootList.get(0).getId() : SystemConstants.TREE_DEFAULT_PARENT_ID);
                    sortChildren(resultList);
                    return resultList;
                },
                RedisCacheConstants.SYS_MARK_CHILD_CODE + mark,
                5 * 60
        );
    }

    private List<SysCodeDto> treeBuilder(List<SysCodeDto> sysCodeDtoList, Long rootId) {
        List<SysCodeDto> groups = new ArrayList<>();

        for (SysCodeDto c1 : sysCodeDtoList) {
            if (Objects.equals(rootId, c1.getParentId())) {
                groups.add(c1);
            }
            for (SysCodeDto c2 : sysCodeDtoList) {
                if (c2.getParentId().equals(c1.getId())) {
                    if (c1.getChildren() == null) {
                        c1.setChildren(new ArrayList<>());
                    }
                    c1.getChildren().add(c2);
                }
            }
        }
        return groups;
    }

    @Override
    public SysCodeDto selectOneWithMarkValue(String mark, String value) {
        List<SysCodeDto> sysCodeDtos = queryListByMark(mark);
        for (SysCodeDto sysCodeDto : sysCodeDtos) {
            if (Objects.equals(sysCodeDto.getValue(), value)) {
                return sysCodeDto;
            }
        }
        return null;
    }

    @Override
    public List<SysCodeDto> queryCodeTree() {
        List<SysCodeEntity> list = sysCodeDao.queryList(new HashMap<>());
        List<SysCodeDto> result = CopyUtils.copyList(list, SysCodeDto.class);
        return result;
    }

    @Override
    public List<SysCodeDto> queryList(Map<String, Object> params) {
        List<SysCodeEntity> sysCodeEntities = sysCodeDao.queryList(params);
        return CopyUtils.copyList(sysCodeEntities, SysCodeDto.class);
    }

    @Override
    public int queryTotal(Map<String, Object> params) {
        return sysCodeDao.queryTotal(params);
    }

    @Override
    public Long save(SysCodeDto dto) {
        SysCodeEntity entity = CopyUtils.copyObj(dto, SysCodeEntity.class);
        entity.setId(Snowflake.nextId());
        sysCodeDao.insert(entity);
        return entity.getId();
    }

    @Override
    public void updateById(SysCodeDto dto) {
        SysCodeEntity entity = CopyUtils.copyObj(dto, SysCodeEntity.class);
        sysCodeDao.updateById(entity);
    }

    @Override
    public void updateAllColumnById(SysCodeDto dto) {

        SysCodeEntity entity = CopyUtils.copyObj(dto, SysCodeEntity.class);


        MyBatisPlusUtils.updateAllColumnById(entity, sysCodeDao);

    }

    @Override
    public SysCodeDto selectById(Long id) {
        SysCodeEntity entity = sysCodeDao.selectById(id);
        return CopyUtils.copyObj(entity, SysCodeDto.class);
    }

    @Override
    public void deleteById(Long id) {
        sysCodeDao.deleteById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String deleteBatch(Long[] ids) {
        Map<String, Object> map = new HashMap<>();
        for (Long id : ids) {
            map.put("parent_id", id);
            List<SysCodeEntity> childrenList = this.sysCodeDao.selectByMap(map);
            if (childrenList != null && childrenList.size() > 0) {
                for (SysCodeEntity s : childrenList) {
                    deleteById(s.getId());
                }
            }
        }
        for (Long id : ids) {
            //删除菜单
            deleteById(id);
        }
        return null;
    }
}
